package com.mazaiting.common.util

import android.content.Context
import android.content.SharedPreferences
import android.os.Build
import androidx.preference.PreferenceManager
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKeys
import com.mazaiting.common.BuildConfig

/**
 * SharedPreferences工具类
 * 单例工具类
 */
class SpUtil private constructor() {

    companion object {
        /** 单例 */
        val instance: SpUtil by lazy { SpUtil() }
        /** 文件名 */
        private const val FILE_NAME = BuildConfig.LIBRARY_PACKAGE_NAME + "_preferences"
    }

    /**
     * 懒加载数据管理对象
     */
    private var preferences: SharedPreferences? = null

    /**
     * 初始化SharedPreferences
     * @Require 必须调用该方法初始化
     * @param context 上下文
     * @param fileName 文件名
     */
    fun init(context: Context, fileName: String = FILE_NAME) {
        preferences = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            // 生成密钥
            val masterKeys = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
            EncryptedSharedPreferences.create(
                fileName, masterKeys, context,
                EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
            )
        } else {
            PreferenceManager.getDefaultSharedPreferences(context)
        }
    }

    /**
     * 存入数据
     * @param key 键
     * @param value 值
     */
    fun put(key: String, value: Any) =
        preferences?.apply {
            // 获取编辑器
            val editor: SharedPreferences.Editor = this.edit()
            // 判断类型并存入
            when (value) {
                is String -> editor.putString(key, value)
                is Int -> editor.putInt(key, value)
                is Boolean -> editor.putBoolean(key, value)
                is Float -> editor.putFloat(key, value)
                is Long -> editor.putLong(key, value)
                else -> editor.putString(key, value.toString())
            }
            // 提交
            editor.apply()
        }

    /**
     * 存入集合数据
     * @param key 键
     * @param value 值
     */
    fun put(key: String, value: Set<String>) =
        preferences?.apply {
            this.edit().putStringSet(key, value).apply()
        }

    /**
     * 根据键获取值
     * @param key 键
     * @param defaultValue 默认值
     * @return 返回对应键的值
     */
    fun getString(key: String, defaultValue: String = "") =
        preferences?.getString(key, defaultValue)

    /**
     * 根据键获取值
     * @param key 键
     * @param defaultValue 默认值
     * @return 返回对应键的值
     */
    fun getBoolean(key: String, defaultValue: Boolean = false): Boolean =
        if (null != preferences) {
            preferences!!.getBoolean(key, defaultValue)
        } else {
            false
        }

    /**
     * 根据键获取值
     * @param key 键
     * @param defaultValue 默认值
     * @return 返回对应键的值
     */
    fun getInt(key: String, defaultValue: Int = 0): Int =
        if (null != preferences) {
            preferences!!.getInt(key, defaultValue)
        } else {
            0
        }

    /**
     * 根据键获取值
     * @param key 键
     * @param defaultValue 默认值
     * @return 返回对应键的值
     */
    fun getLong(key: String, defaultValue: Long = 0L): Long =
        if (null == preferences) {
            preferences!!.getLong(key, defaultValue)
        } else {
            0L
        }

    /**
     * 根据键获取值
     * @param key 键
     * @param defaultValue 默认值
     * @return 返回对应键的值
     */
    fun getFloat(key: String, defaultValue: Float = 0.0F): Float =
        if (null == preferences) {
            preferences!!.getFloat(key, defaultValue)
        } else {
            0.0F
        }

    /**
     * 获取集合数据
     * @param key 键
     * @return 返回集合
     */
    fun getSet(key: String): Set<String>? =
        if (null == preferences) {
            preferences!!.getStringSet(key, null)
        } else {
            null
        }

    /**
     * 移除键
     * @param key 键
     */
    fun remove(key: String) =
        preferences?.apply { this.edit().remove(key).apply() }

    /**
     * 判断是否包含键
     * @param key 键
     * @return true: 包含; false: 不包含
     */
    fun contains(key: String): Boolean =
        if (null != preferences) {
            preferences!!.contains(key)
        } else {
            false
        }

    /**
     * 获取所有的键值
     * @return Map
     */
    fun getAll(): MutableMap<String, *>? = preferences?.all

    /**
     * 注册数据改变监听
     * @param listener 监听
     */
    fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) =
        preferences?.registerOnSharedPreferenceChangeListener(listener)

    /**
     * 取消注册数据改变监听
     */
    fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) =
        preferences?.unregisterOnSharedPreferenceChangeListener(listener)

}